import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_storekit/store_kit_wrappers.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../../../data/db/models/bt_order.dart';
import '../../../data/db/providers/bt_order_provider.dart';
import '../../../data/models/bt_recharge.dart';
import '../../../data/store/bt_hive_logon_store.dart';
import '../../../data/store/bt_logon_data.dart';
import '../../utils/bt_constants.dart';
import '../../../data/models/bt_goods.dart';
import '../../utils/bt_event_bus.dart';
import '../repository/bt_order_repository.dart';

class BtCoinShopModel extends ChangeNotifier {
  final int _pageSize = 20;

  final PagingController<int, BtGoods> _pagingController = PagingController(firstPageKey: 0);

  PagingController<int, BtGoods> get pagingController => _pagingController;

  late PageRequestListener<int> _listener;

  late final BtOrderRepository repository;

  String _userServiceId = '';

  String get userServiceId => _userServiceId;

  int _availableCoins = 0;

  int get availableCoins => _availableCoins;

  StreamSubscription? _subscription;

  BtCoinShopModel() {
    repository = BtOrderRepository();
    BtHiveLogonStore().getData().then((result) {
      _availableCoins = result?.availableCoins ?? 0;
      notifyListeners();
    });
    _listener = (pageKey) {
      pageKey++;
      fetchBtGoodsList(pageKey);
    };
    _pagingController.addPageRequestListener(_listener);

    fetchUserServiceId();
  }

  Future<void> fetchUserServiceId() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    _userServiceId = prefs.getString(userServiceAccountId) ?? '';

    notifyListeners();
  }

  void fetchBtGoodsList(int pageKey) {
    repository.fetchBtGoodsList(pageKey, _pageSize, (btBtGoodsList) {
      try {
        final newItems = btBtGoodsList;
        final isLastPage = newItems.length < _pageSize;
        if (isLastPage) {
          _pagingController.appendLastPage(newItems);
        } else {
          _pagingController.appendPage(newItems, pageKey);
        }
      } catch (error) {
        _pagingController.error = error;
      }
    });
  }

  void purchase(BtGoods goods, Function(bool success, String msg, String orderNo) onResult) async {
    final transactions = await SKPaymentQueueWrapper().transactions();
    for (var transaction in transactions) {
      await SKPaymentQueueWrapper().finishTransaction(transaction);
    }
    EasyLoading.show();
    _subscription?.cancel();

    try {
      repository.recharge(goods.code, (bool success, String msg, BtRecharge? orderData) async {
        if (success) {
          final Stream purchaseUpdated = InAppPurchase.instance.purchaseStream;
          _subscription = purchaseUpdated.listen((purchaseDetailsList) async {
            purchaseDetailsList = purchaseDetailsList as List<PurchaseDetails>;
            for (var purchaseDetails in purchaseDetailsList) {
              if (kDebugMode) {
                print("purchaseDetails : ${purchaseDetails.status.name}");
              }
              if (purchaseDetails.status == PurchaseStatus.pending) {
                EasyLoading.show();
              } else if (purchaseDetails.error != null) {
                if (purchaseDetails.status == PurchaseStatus.canceled) {
                  onResult(false, 'Purchase Canceled', '');
                } else if (purchaseDetails.status == PurchaseStatus.error) {
                  onResult(false, 'Purchase Error:${purchaseDetails.error?.message ?? ''}', '');
                }
                _subscription?.cancel();
                InAppPurchase.instance.completePurchase(purchaseDetails);
              } else if (purchaseDetails.status == PurchaseStatus.purchased) {
                repository.rechargePayment(
                    orderData?.orderNo ?? '',
                    purchaseDetails.verificationData.serverVerificationData,
                    purchaseDetails.purchaseID ?? '', (success, msg) async {
                  if (success) {
                    _addCoins(goods.exchangeCoin);
                    BtOrderProvider().insert(BtOrder(
                      goodsCode: orderData?.goodsCode ?? '',
                      goodsName: orderData?.goodsName ?? '',
                      orderNo: orderData?.orderNo ?? '',
                      payAmount: '${orderData?.payAmount ?? 0.0}',
                      paidAmount: '${orderData?.paidAmount ?? 0.0}',
                      paidCurrency: orderData?.paidCurrency ?? '',
                    ));
                    await InAppPurchase.instance.completePurchase(purchaseDetails);
                    onResult(true, 'Purchase Successfully', orderData?.orderNo ?? '');
                  } else {
                    await InAppPurchase.instance.completePurchase(purchaseDetails);
                    onResult(false, 'Purchase Fail: $msg', '');
                  }
                  EasyLoading.dismiss();
                  _subscription?.cancel();
                });
              } else if (purchaseDetails.status == PurchaseStatus.restored) {
                onResult(false, 'Purchase restore:${purchaseDetails.productID}', '');
                InAppPurchase.instance.completePurchase(purchaseDetails);
                _subscription?.cancel();
              }
            }
          }, onDone: () {
            if (kDebugMode) {
              print("onDone");
            }
            _subscription?.cancel();
            EasyLoading.dismiss();
          }, onError: (error) {
            if (kDebugMode) {
              print("onError:$error");
            }
            _subscription?.cancel();
            EasyLoading.dismiss();
          });
          var data = await loadAppleIds([goods.code]);
          if (data.isNotEmpty) {
            var productDetail = data[0];
            var purchaseParam = PurchaseParam(productDetails: productDetail);
            await InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam);
          } else {
            EasyLoading.dismiss();
            _subscription?.cancel();
          }
        } else {
          onResult(false, msg, '');
          _subscription?.cancel();
        }
      });
    } catch (e) {
      onResult(false, e.toString(), '');
      _subscription?.cancel();
    }
  }

  Future<List<ProductDetails>> loadAppleIds(List<String> productIds) async {
    Set<String> kIds = productIds.toSet();
    final ProductDetailsResponse response = await InAppPurchase.instance.queryProductDetails(kIds);
    if (response.notFoundIDs.isNotEmpty) {
      EasyLoading.showToast("Not FoundIDs ${response.notFoundIDs}");
    }
    List<ProductDetails> products = response.productDetails;
    return products;
  }

  Future<void> _addCoins(int coins) async {
    var data = await BtHiveLogonStore().getData();
    await BtHiveLogonStore().putData(BtLogonData(
      token: data!.token,
      userId: data.userId,
      userType: data.userType,
      nickname: data.nickname,
      avatarUrl: data.avatarUrl,
      avatarThumbUrl: data.avatarThumbUrl,
      loginPkgName: data.loginPkgName,
      country: data.country,
      birthday: data.birthday,
      availableCoins: data.availableCoins + coins,
    ));
    _availableCoins = data.availableCoins + coins;
    eventBus.fire(BtEventFn(freshAvailableCoins));

    notifyListeners();
  }

  @override
  void dispose() {
    super.dispose();
    _subscription?.cancel();
  }
}
